Differentiation#

강좌: 수치해석

Finite Difference#

Taylor expansion 을 이용하면 수치 미분을 구할 수 있다.

First-order derivative#

fd-fig

Fig. 20 Finite Difference (from Wikipedia)#

  • Forward Difference

\[ f'(x_j) = \frac{f(x_{j+1}) - f(x_j)}{\Delta x} + O(\Delta x) \approx \frac{\Delta f(x)}{\Delta x} \]
  • Backward Differnce

\[ f'(x_j) = \frac{f(x_{j}) - f(x_{j-1})}{\Delta x} + O(\Delta x) \approx \frac{\nabla f(x)}{\Delta x} \]
  • Central Difference

    • 다음 두 식을 빼보자.

\[ f(x_{j+1}) = f(x_j) + \Delta x f'(x_j) + \frac{(\Delta x)^2}{2} f''(x_j) + \frac{(\Delta x)^3}{3!} f'''(x_j) + O((\Delta x)^2) \]
\[ f(x_{j-1}) = f(x_j) - \Delta x f'(x_j) + \frac{(\Delta x)^2}{2} f''(x_j) - \frac{(\Delta x)^3}{3!} f'''(x_j) + O((\Delta x)^3) \]
  • 그 결과는 다음과 같다.

\[ f'(x_j) = \frac{f(x_{j+1}) - f(x_{j-1})}{ 2\Delta x} + O((\Delta x)^2) \approx \frac{\delta f(x)}{2 \Delta x} \]

Second-order derivative#

  • Central Difference

    • 위의 두 식을 더한 후 \(2 f(x_j)\) 를 빼보자.

\[ f''(x_j) = \frac{f(x_{j+1}) + 2 f(x_j) - f(x_{j-1})}{ (\Delta x)^2} + O((\Delta x)^2) \]

제차분식#

  • Second-order Central

    \[ f''(x) \approx \frac{\delta^2 f(x) }{ (\Delta x)^2} = \frac{\Delta f(x) - \nabla f(x) }{\Delta x} = \frac{f(x_{j+1}) + 2 f(x_j) - f(x_{j-1})}{ (\Delta x)^2} \]
    • \(E=O((\Delta x)^2)\)

  • Second-order Forward

    \[ f''(x) \approx \frac{\Delta^2 f(x) }{ (\Delta x)^2} = \frac{\Delta f(x+\Delta x) - \Delta f(x) }{\Delta x} = \frac{f(x_{j+2}) - 2 f(x_{j+1}) + f(x_{j})}{ (\Delta x)^2} \]
    • \(E=O((\Delta x))\)

  • Second-order Backward

    \[ f''(x) \approx \frac{\nabla^2 f(x) }{ (\Delta x)^2} = \frac{\nabla f(x) - \nabla f(x - \Delta x) }{\Delta x} = \frac{f(x_{j}) - 2 f(x_{j-1}) + f(x_{j-2})}{ (\Delta x)^2} \]
    • \(E=O((\Delta x))\)

General approaches#

  • 일반적인 방법

    • 여러 Taylor expansion의 합차를 이용해서 원하는 미분항의 근사식을 구한다.

예제#

\(f(x)=\sin(x)\) 에 대해서 수치 미분 결과를 비교하자.

%matplotlib inline
from matplotlib import pyplot as plt

import numpy as np

plt.style.use('ggplot')
plt.rcParams['figure.dpi'] = 150
x = 0.2*np.pi
dx = 0.01*np.pi
f = np.sin

# First-order forward 
fdf = (f(x+dx) - f(x)) / dx

# First-order backward
bdf = (f(x) - f(x-dx)) / dx

# First-order central
cdf = (f(x+dx) - f(x-dx)) / (2*dx)

print("Exact: ", np.cos(x))
print(fdf, bdf, cdf)
Exact:  0.8090169943749475
0.7996517731793618 0.8181160727815516 0.8088839229804567
# Exact difference
df = np.cos(x)

# Reducing dx and confirm errors
dxs = [0.01*np.pi, 0.005*np.pi, 0.0025*np.pi, 0.00125*np.pi, 0.000625*np.pi]

# Fowrad difference
err_fw = []
for dx in dxs:
    fdf = (f(x+dx) - f(x)) / dx
    err_fw.append(abs((fdf -df)/df))
    
# Backward difference
err_bw = []
for dx in dxs:
    bdf = (f(x) - f(x-dx)) / dx
    err_bw.append(abs((bdf -df)/df))    
    
# Central difference
err_ct = []
for dx in dxs:
    cdf = (f(x+dx) - f(x-dx)) / (2*dx)
    err_ct.append(abs((cdf -df)/df))       
    
# Plot log-log graph    
plt.loglog(dxs, err_fw)
plt.loglog(dxs, err_bw)
plt.loglog(dxs, err_ct)

# Same scale of x and y
plt.axis('equal')

# Legend
plt.legend([
    'Forward difference',
    'Backward difference',
    'Central difference',
])

plt.xlabel('x')
plt.ylabel('$\epsilon$')
Text(0, 0.5, '$\\epsilon$')
../_images/491d847228b65d15fea4116b6f8df607556afe328a9a1798d6cc582145bba3d8.png